/*
* Copyright (C) 2020 ~ 2024 chaigec All Rights Reserved.
*
* Author:     chaigec <chaigec@163.com>
* Maintainer: chaigec <chaigec@163.com>

 * Use of this source code is governed by MIT license that can be found in the
 * LICENSE file in the root of the source tree. All contributing project authors
 * may be found in the AUTHORS file in the root of the source tree.
*/
#include "MkSipMessage.h"
#include "MkSipUtil.h"
#include "MkSipHeader.h"
#include "MkUtil/MkUtil.h"
#include "MkUtil/MkLog.h"

CMkSipMessage::CMkSipMessage()
    : m_ParseHeaderEnd(FALSE)
    , m_ContentLenght(0)
    , m_bRequest(TRUE)
    , m_Method(MkSipMethodEnd)
    , m_StatusCode(MkSipStatusEnd)
    , m_Version("SIP/2.0")
    , m_MaxForwards(70)
    , m_bTcp(FALSE)
{

}

Uint32 CMkSipMessage::ParseContent(const Uint8* pBuf, Uint32 nLen, Uint32& nUsed)
{
    Uint32 ErrorCode = NoneError;
    if (!m_ParseHeaderEnd) {
        Uint32 nHeadLen;
        ErrorCode = CMkUtil::ReadTextProtocolHead((const Int8*)pBuf, nLen, nHeadLen);
        if (NoneError != ErrorCode) {
            return NotHasEnoughBuffer;
        }
        nUsed = nHeadLen;

        MkString strLine;
        Uint32 nPos = 0;
        ErrorCode = CMkUtil::ReadLine((const Int8*)pBuf, nHeadLen, nPos, strLine);
        MkCheckErrorLog(ErrorCode, "read sip header line failed\n");
        if (strLine.empty()) {
            return NoneError;
        }

        ErrorCode = ParseHeaderLine(strLine);
        MkCheckErrorLog(ErrorCode, "parse header line:%s failed\n", strLine.c_str());

        MkString strKey;
        MkString strValue;
        while (1) {
            ErrorCode = CMkUtil::ReadLine((const Int8*)(pBuf), nHeadLen, nPos, strLine);
            if (NoneError != ErrorCode
                || strLine.empty()) {
                break;
            }
            ErrorCode = ParseHeader(strLine, strKey, strValue);
            if (NoneError == ErrorCode) {
                AddHeader(strKey, strValue);
            }
        }
        m_ParseHeaderEnd = TRUE;
    }
    if (m_ParseHeaderEnd) {
        if (nLen - nUsed < m_ContentLenght) {
            return NotHasEnoughBuffer;
        }
        m_ContentBody = MkString((const Int8*)(pBuf + nUsed), m_ContentLenght);
        nUsed += m_ContentLenght;
    }
    return NoneError;
}

Uint32 CMkSipMessage::ToString(MkString& Content) const
{
    MkString strDesc;
    Uint32 ErrorCode = NoneError;
    if (m_bRequest) {
        ErrorCode = CMkSipUtil::GetInstance().GetSipStringMethod(m_Method, strDesc);
        MkCheckErrorLog(ErrorCode, "get sip method failed\n");
        MkString strUri;
        m_Uri.ToString(strUri);
        Content = strDesc + " " + strUri + " " + m_Version + MkEndLine;
    } else {
        ErrorCode = CMkSipUtil::GetInstance().GetStatusCodeDesc(m_StatusCode, strDesc);
        MkCheckErrorLog(ErrorCode, "get status code failed\n");
        Content = m_Version + " " + std::to_string(m_StatusCode) + " " + strDesc + MkEndLine;
    }
    MkString strValue;

    //add via
    MkList<CMkSipVia>::const_iterator itVia = m_VecVia.begin();
    for (; itVia != m_VecVia.end(); itVia++) {
        itVia->ToString(strValue);
        Content += "Via: " + strValue + MkEndLine;
    }

    //add from
    strValue.clear();
    m_From.ToString(strValue);
    Content += "From: " + strValue + MkEndLine;

    //add to
    strValue.clear();
    m_To.ToString(strValue);
    Content += "To: " + strValue + MkEndLine;

    //add callid
    Content += "Call-ID: " + m_CallId.first;
    if (!m_CallId.second.empty()) {
        Content += "@" + m_CallId.second;
    }
    Content += MkEndLine;

    //add CSeq
    Content += "CSeq: " + std::to_string(m_CSeq.first) + " " + m_CSeq.second + MkEndLine;

    //add contact
    MkVector<CMkSipContact>::const_iterator itContact = m_VecContact.begin();
    for (; itContact != m_VecContact.end(); itContact++) {
        MkString strContact;
        itContact->ToString(strContact);
        Content += "Contact: " + strContact + MkEndLine;
    }

    //add route
    MkVector<CMkSipRoute>::const_iterator itRoute = m_VecRoute.begin();
    for (; itRoute != m_VecRoute.end(); itRoute++) {
        MkString strRoute;
        itRoute->ToString(strRoute);
        Content += "Route: " + strRoute + MkEndLine;
    }

    //add record route
    MkVector<CMkSipRecordRoute>::const_iterator itRecordRoute = m_VecRecordRoute.begin();
    for (; itRecordRoute != m_VecRecordRoute.end(); itRecordRoute++) {
        MkString strRoute;
        itRecordRoute->ToString(strRoute);
        Content += "Record-Route: " + strRoute + MkEndLine;
    }

    //add content type
    if (!m_ContentType.IsEmpty()) {
        strValue.clear();
        m_ContentType.ToString(strValue);
        Content += "Content-Type: " + strValue + MkEndLine;
    }

    if (m_bRequest) {
        Content += "Max-Forwards: " + std::to_string(m_MaxForwards) + MkEndLine;
    }
    Content += "User-Agent: " + MkString(MkUserAgent) + MkEndLine;
    //add other headers
    MkMapString::const_iterator itOther = m_MapOtherHeader.begin();
    for (; itOther != m_MapOtherHeader.end(); itOther++) {
        Content += itOther->first + ": " + itOther->second + MkEndLine;
    }

    //add content lenght
    Content += "Content-Length: " + std::to_string(m_ContentLenght) + MkEndLine;
    Content += MkEndLine;

    if (!m_ContentBody.empty()) {
        Content += m_ContentBody;
    }
    return NoneError;
}

void CMkSipMessage::SetContentType(const MkSipContentType& SipContentType)
{
    CMkSipContentType TypeContent;
    switch (SipContentType) {
    case MkSipContentXml:
        TypeContent.SetType("Application");
        TypeContent.SetSubType("MANSCDP+xml");
        break;
    case MkSipContentSdp:
        TypeContent.SetType("application");
        TypeContent.SetSubType("sdp");
        break;
    case MkSipContentRtsp:
        TypeContent.SetType("application");
        TypeContent.SetSubType("rtsp");
        break;
        break;
    default:
        break;
    }
    return SetContentType(TypeContent);
}

void CMkSipMessage::AddHeader(const MkString& strKey, const MkString& strValue)
{
    Uint32 ErrorCode = NoneError;
    if ("Call-ID" == strKey) {
        MkVectorString VecStr;
        ErrorCode = CMkUtil::StringSplit(strValue, " ", VecStr);
        m_CallId.first = VecStr[0];
        if (VecStr.size() > 1) {
            m_CallId.second = VecStr[1];
        }
    } else if ("Via" == strKey) {
        CMkSipVia SipVia;
        SipVia.Parse(strValue);
        m_VecVia.push_back(SipVia);
    } else if ("From" == strKey) {
        m_From.Parse(strValue);
    } else if ("To" == strKey) {
        m_To.Parse(strValue);
    } else if ("CSeq" == strKey) {
        MkVectorString VecStr;
        ErrorCode = CMkUtil::StringSplit(strValue, " ", VecStr);
        if (NoneError == ErrorCode
            && VecStr.size() > 1) {
            m_CSeq.first = std::stoi(VecStr[0]);
            m_CSeq.second = VecStr[1];
        }
    } else if ("Contact" == strKey) {
        CMkSipContact Contact;
        Contact.Parse(strValue);
        m_VecContact.push_back(Contact);
    } else if ("Content-Length" == strKey) {
        m_ContentLenght = std::stoi(strValue);
    } else if ("Authorization" == strKey) {
        CMkSipAuthorization Authorization;
        Authorization.Parse(strValue);
        m_VecAuthorization.push_back(Authorization);
    } else if ("WWW-Authenticate" == strKey) {
        CMkSipWwwAuthenticate WwwAuthenticate;
        WwwAuthenticate.Parse(strValue);
        m_VecWwwAuthenticate.push_back(WwwAuthenticate);
    } else if ("Content-Type" == strKey) {
        m_ContentType.Parse(strValue);
    } else {
        m_MapOtherHeader.insert(std::pair<MkString, MkString>(strKey, strValue));
    }
}

void CMkSipMessage::AddOtherHeaders(const MkMapString& MapHeader)
{
    m_MapOtherHeader.insert(MapHeader.begin(), MapHeader.end());
}

void CMkSipMessage::SetCSeq(Uint32 SeqNo)
{
    m_CSeq.first = SeqNo;
    CMkSipUtil::GetInstance().GetSipStringMethod(m_Method, m_CSeq.second);
}

Uint32 CMkSipMessage::GetHeaderValue(const MkString& strKey, MkString& strValue) const
{
    MkMapString::const_iterator it = m_MapOtherHeader.find(strKey);
    if (it != m_MapOtherHeader.end()) {
        strValue = it->second;
        return NoneError;
    }
    return InvalidParams;
}

Uint32 CMkSipMessage::ParseHeaderLine(const MkString& strLine)
{
    MkVectorString VecString;
    Uint32 ErrorCode = CMkUtil::StringSplit(strLine, " ", VecString);
    MkCheckErrorLog(ErrorCode, "split string:%s failed\n", strLine.c_str());

    //header mast 3 part
    if (3 <= VecString.size()) {
        if ("SIP/2.0" == VecString[2]) {
            m_bRequest = TRUE;
            m_Version = VecString[2];
            m_Uri.Parse(VecString[1]);
            return CMkSipUtil::GetInstance().GetSipMethod(VecString[0], m_Method);
        } else if ("SIP/2.0" == VecString[0]) {
            m_bRequest = FALSE;
            m_Version = VecString[0];
            m_StatusCode = (MkSipStatus)std::stoi(VecString[1]);
            return NoneError;
        }
    }

    MkErrorLog("header line:%s invalid\n", strLine.c_str());
    return InvalidParams;
}

Uint32 CMkSipMessage::ParseHeader(const MkString& strHeader, MkString& Key, MkString& Value)
{
    MkVectorString VecString;
    Uint32 ErrorCode = CMkUtil::StringSplit(strHeader, ": ", VecString);
    MkCheckErrorLog(ErrorCode, "split string:%s failed\n", strHeader.c_str());
    if (VecString.size() < 2) {
        return InvalidParams;
    }
    Key = VecString[0];
    Value = VecString[1];
    return NoneError;
}

MkString CMkSipMessage::GetTransactionId() const
{
    if (m_VecVia.empty()
        || m_CallId.first.empty()) {
        return CMkUtil::GetEmptyString();
    }
    //via branch, cseq,
    return m_VecVia.begin()->GetBranch() + std::to_string(m_CSeq.first) + m_CallId.first;
}

const MkString& CMkSipMessage::GetDialogId() const
{
    //MkString FromTag;
    //m_From.GetParamValue("tag", FromTag);
    return m_CallId.first;/* +FromTag;*/
}

CMkSipMessage::~CMkSipMessage()
{

}
